Xceed Zip for COM/ActiveX on x86/x64 Documentation
Example topics / Compress method example for VC++
In This Topic
    Compress method example for VC++
    In This Topic

    This example shows the use of the Compress and Uncompress methods in C++. The example focuses on the handling of the VARIANT data structure on a low-level so you can see how the magic works. The example also shows how different types of data can be compressed and uncompressed, namely strings, unicode strings and raw data.

    The example code below is ready to compile and run into a console C++ application.

    VC++ Copy Code

    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
    #include <stdio.h>

    #import "XceedZip.dll" named_guids no_namespace

    template< class DataType > static void PrintByteArrayVariant( VARIANT * variant );
    static void PrintVariantAsString( VARIANT * variant );
    static void PrintVariantAsUnicodeString( VARIANT * variant );

    static void StringExample( IXceedCompressionPtr & compression, const char * data )
    {
      xcdCompressionError error;
      VARIANT dataToCompress;
      VARIANT compressedData;
      VARIANT uncompressedData;
      SAFEARRAY * safeArray;
      char * safeArrayData;
      size_t length;

      /* The VARIANT structure doesn't directly support 8-bit strings. We will
         have to supply the string as a byte array.
        
         We will not compress the terminating null character. */

      // Compute the length of the string
      length = strlen( data );

      // Create a one-dimensional array using the length (excluding the null character)
      safeArray = SafeArrayCreateVector( VT_I1, 0, length );
     
      // Access the array data and copy the string to the array
      SafeArrayAccessData( safeArray, ( void ** ) &safeArrayData );
      CopyMemory( safeArrayData, data, length );
      SafeArrayUnaccessData( safeArray );

      // Initialize the variants we will use
      VariantInit( &dataToCompress );
      VariantInit( &compressedData );
      VariantInit( &uncompressedData );

      // Set the data type to an array of bytes
      dataToCompress.vt = VT_ARRAY | VT_I1;
     
      // Assign the safe array to the VARIANT. Responsability is transfered
      dataToCompress.parray = safeArray;

      // Compress the data
      error = compression->Compress( &dataToCompress, &compressedData, VARIANT_TRUE );

      // We no longer need the data to compress
      VariantClear( &dataToCompress );

      if ( error != xceSuccess )
        throw new _com_error( error );

      /* compressedData now contains an array of bytes. This is not a string. It is the
         compressed data and is not in a specific form.

         In this example, we will display each byte in the array as an hexadecimal value.
         In a real application, the data in the array could be saved in a file, sent to another
         computer, whatever. */

      printf( "Begin compressed data:\n" );
      PrintByteArrayVariant< unsigned char >( &compressedData );
      printf( "\nEnd compressed data.\n\n" );

      // Uncompress the data
      error = compression->Uncompress( &compressedData, &uncompressedData, VARIANT_TRUE );

      // We no longer need the compressed data
      VariantClear( &compressedData );

      if ( error != xceSuccess )
        throw new _com_error( error );

      printf( "Begin uncompressed data:\n" );
      PrintVariantAsString( &uncompressedData );
      printf( "\nEnd uncompressed data.\n\n" );

      // Clear the uncompressed data
      VariantClear( &uncompressedData );
    }

    static void UnicodeStringExample( IXceedCompressionPtr & compression, const wchar_t * data )
    {
      xcdCompressionError error;
      VARIANT dataToCompress;
      VARIANT compressedData;
      VARIANT uncompressedData;
      _bstr_t bstring;

      /* The VARIANT structure doesn't support straight unicode strings. But it does
         support something close to it. Something called BSTR.

         A BSTR, known as basic string or binary string, is a pointer to a wide
         character string used by Automation data manipulation functions.

         We will use the COM _bstr_t helper class to build the BSTR out of the
         supplied unicode string. */

      // Copy the supplied unicode string data to the BSTR object
      bstring = data;

      // Initialize the variants we will use
      VariantInit( &dataToCompress );
      VariantInit( &compressedData );
      VariantInit( &uncompressedData );

      // Set the data type to BSTR
      dataToCompress.vt = VT_BSTR;
     
      // Assign the safe array to the VARIANT. Responsability is transfered
      dataToCompress.bstrVal = bstring;

      // Compress the data
      error = compression->Compress( &dataToCompress, &compressedData, VARIANT_TRUE );

      // We no longer need the data to compress
      VariantClear( &dataToCompress );

      if ( error != xceSuccess )
        throw new _com_error( error );

      /* compressedData now contains an array of bytes. This is not a string. It is the
         compressed data and is not in a specific form.

         In this example, we will display each byte in the array as an hexadecimal value.
         In a real application, the data in the array could be saved in a file, sent to another
         computer, whatever. */

      printf( "Begin compressed data:\n" );
      PrintByteArrayVariant< unsigned char >( &compressedData );
      printf( "\nEnd compressed data.\n\n" );

      // Uncompress the data
      error = compression->Uncompress( &compressedData, &uncompressedData, VARIANT_TRUE );

      // We no longer need the compressed data
      VariantClear( &compressedData );

      if ( error != xceSuccess )
        throw new _com_error( error );

      printf( "Begin uncompressed data:\n" );
      PrintVariantAsUnicodeString( &uncompressedData );
      printf( "\nEnd uncompressed data.\n\n" );

      // Clear the uncompressed data
      VariantClear( &uncompressedData );
    }

    static void RawDataExample( IXceedCompressionPtr & compression, unsigned long * data, int count )
    {
      xcdCompressionError error;
      VARIANT dataToCompress;
      VARIANT compressedData;
      VARIANT uncompressedData;
      SAFEARRAY * safeArray;
      unsigned long * safeArrayData;
      size_t size;

      /* Although the VARIANT structure supports 4 byte unsigned integers, the Compress
         function only accepts BSTR or byte arrays in its VARIANT source parameter.
        
         We will therefore have to supply the data as a byte array. */

      // Compute the size in bytes of the supplied data
      size = count * sizeof( unsigned long );

      // Create a one-dimensional array of unsigned bytes
      safeArray = SafeArrayCreateVector( VT_UI1, 0, size );
     
      // Access the array data and copy the data to the array
      SafeArrayAccessData( safeArray, ( void ** ) &safeArrayData );
      CopyMemory( safeArrayData, data, size );
      SafeArrayUnaccessData( safeArray );

      // Initialize the variants we will use
      VariantInit( &dataToCompress );
      VariantInit( &compressedData );
      VariantInit( &uncompressedData );

      // Set the data type to an array of unsigned bytes
      dataToCompress.vt = VT_ARRAY | VT_UI1;
     
      // Assign the safe array to the VARIANT. Responsability is transfered
      dataToCompress.parray = safeArray;

      // Compress the data
      error = compression->Compress( &dataToCompress, &compressedData, VARIANT_TRUE );

      // We no longer need the data to compress
      VariantClear( &dataToCompress );

      if ( error != xceSuccess )
        throw new _com_error( error );

      /* compressedData now contains an array of bytes. This is not a string. It is the
         compressed data and is not in a specific form.

         In this example, we will display each byte in the array as an hexadecimal value.
         In a real application, the data in the array could be saved in a file, sent to another
         computer, whatever. */

      printf( "Begin compressed data:\n" );
      PrintByteArrayVariant< unsigned char >( &compressedData );
      printf( "\nEnd compressed data.\n\n" );

      // Uncompress the data
      error = compression->Uncompress( &compressedData, &uncompressedData, VARIANT_TRUE );

      // We no longer need the compressed data
      VariantClear( &compressedData );

      if ( error != xceSuccess )
        throw new _com_error( error );

      printf( "Begin uncompressed data:\n" );
      PrintByteArrayVariant< unsigned long >( &uncompressedData );
      printf( "\nEnd uncompressed data.\n\n" );

      // Clear the uncompressed data
      VariantClear( &uncompressedData );
    }

    template< class DataType > static void PrintByteArrayVariant( VARIANT * variant )
    {
      DataType * data;
      SAFEARRAY * arrayDescriptor;
      int i, count;

      // Get the array descriptor from the variant
      arrayDescriptor = variant->parray;

      // Gain access to the array data
      SafeArrayAccessData( arrayDescriptor, ( void ** ) &data );

      // Get the number of elements in the first dimension of the array
      count = arrayDescriptor->rgsabound[ 0 ].cElements / sizeof( DataType );

      int lineThreshold = 32 / sizeof( DataType );
      int groupThreshold = 4 / sizeof( DataType );
      char buffer[ 16 ];

      sprintf( buffer, "%%0%dX", sizeof( DataType ) * 2 );
     
      for( i = 0; i < count; i++ )
      {
        // If we need to change line
        if( ( i % lineThreshold ) == 0 && i > 0 )
          printf( "\n" );

        // If we need to seperate a group of data
        if( ( i % groupThreshold ) == 0 )
          printf( " " );

        // Access the current index as we would a normal array
        printf( buffer, data[ i ] );
      }

      // Release access to the array data
      SafeArrayUnaccessData( arrayDescriptor );
    }

    static void PrintVariantAsString( VARIANT * variant )
    {
      char * string;
      SAFEARRAY * arrayDescriptor;
      int i, count;

      // Get the array descriptor from the variant
      arrayDescriptor = variant->parray;

      // Gain access to the array data
      SafeArrayAccessData( arrayDescriptor, ( void ** ) &string );

      // Get the number of elements in the first dimension of the array
      count = arrayDescriptor->rgsabound[ 0 ].cElements;

      /* Since the uncompressed data doesn't contain the terminating null character
         we either have to print the string one character at a time knowing the
         lenght of the array. Or, we can copy the data to another buffer that has the
         size to contain the null character.

         Here, we choose to print one character at a time. */
     
      for( i = 0; i < count; i++ )
      {
        // Print the current character
        printf( "%c", string[ i ] );
      }

      // Release access to the array data
      SafeArrayUnaccessData( arrayDescriptor );
    }

    static void PrintVariantAsUnicodeString( VARIANT * variant )
    {
      HRESULT result;

      /* We need to convert the variant type from whatever (usually byte array in
         our examples) to BSTR. We will show how this is done when no helper classes
         are used.
        
         The VariantChangeType function does this. We will attempt to make this
         conversion in place (meaning to replace the current data with the converted
         data. */

      // Convert the variant data to a BSTR
      result = VariantChangeType( variant, variant, 0, VT_BSTR );

      // If the conversion was successful
      if( result == S_OK )
      {
        /* We will use the COM BSTR wrapper class to easily access the actual
           string. But we will NOT copy the string data */

        // Wrap the BSTR without copying the data
        _bstr_t bString( variant->bstrVal, false );

        // BSTR strings are unicode
        const wchar_t * actualString = bString;

        // Print the unicode string
        wprintf( L"%s", actualString );
      }
    }

    int main( int argc, char * argv[] )
    {
      CoInitialize( NULL );

      try
      {
        char textData[] =
          "It's actually 607 small islands in the South Pacific. "
          "Interestingly, while its total land mass is only 270 square miles, "
          "it occupies more than a million square miles of the Pacific Ocean. "
          "Population is 127,000 and the U.S. Embassy is located in the state of "
          "Pohnpei and not, as many people believe, on the island of Yap.";

        wchar_t unicodeTextData[] =
          L"You need to listen to me. You have to listen to me. I can't help you, unless you listen "
          L"to me! You can't send Christmas cards to everyone, you can't do it! Forget the "
          L"SPR, let's get the IMF loans like we said we were going to, listen to what I have to say "
          L"about Didion, and please, listen to me!";

        unsigned long rawData[] = { 0xFEEEEEEE, 0x80018001, 0x00000000, 0xFFFFFFFF, 0x36FE0006 };

        // Create the XceedCompression object
        IXceedCompressionPtr compression( CLSID_XceedCompression );
       
        // License the object
        if( compression->License( _bstr_t( L"your license key" ) ) == VARIANT_FALSE )
        {
          printf( "License() failed.\n" );
          return 1;
        }

        /* There are several ways to manipulate VARIANT data. In this example, we will
           try to show how VARIANT data is handled without 'magic' so we will use the VARIANT
           structure directly.

           The COM helper class _variant_t encapsulates a VARIANT structure and provides
           useful methods to work with it.

           In MFC, the COleVariant class also encapsulates the VARIANT structure.

           All the operations done on VARIANTs in these examples can be seen as simple
           methods in the _variant_t or COleVariant classes.

           In order to keep this example from becoming too heavy, we will use the COM
           helper class _bstr_t that provides a useful wrapper around the BSTR data type. */
      
        // A compression/decompression example using a string as data
        StringExample( compression, textData );

        // A compression/decompression example using a unicode string as data
        UnicodeStringExample( compression, unicodeTextData );

        // A compression/decompression example using raw data
        RawDataExample( compression, rawData, sizeof( rawData ) / sizeof( unsigned long ) );
      }
      catch( const _com_error& error )
      {
        printf( "COM error %08x. %S\n", error.Error(), ( const char* ) error.Description() );
      }
      catch( ... )
      {
        printf( "Unexpected error\n" );
      }

      CoUninitialize();
      return 0;
    }